/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package elsimulatorjava;

import java.util.ArrayList;
import java.util.Date;
import java.util.Set;
import java.util.Iterator;
import java.util.HashSet;

/**
 *
 * @author jc238592
 */
public class Elevator {

    private static int elevatorCounter = 0;
    private int index;
    
   /*- public Signal2<Integer, Integer> currentFloorChanged = new Signal2<Integer, Integer>();
    public Signal2<Integer, Boolean> doorStateChanged = new Signal2<Integer, Boolean>();
    public Signal2<Integer, Boolean> directionChanged = new Signal2<Integer, Boolean>();
    public Signal2<Integer, Integer> peopleInElevatorChanged = new Signal2<Integer, Integer>();*/
    
    private ArrayList<Boolean> floorList;
    private Set<Integer> queue;
    
    private Date timer;
    private Date doorTimer;
    private int people;
    private int capacity;
    private int minFloor;
    private int maxFloor;
    private int currentFloor;
    private int nextFloor;
    private boolean moving; // is the elevator moving
    private boolean goingUp;
    private boolean doorClosed;
    private boolean doorActionAttempt;
    private boolean emergencyStop;

    /*
     * Elevator constructor
     */
    Elevator(int minF, int maxF, ArrayList<Boolean> fl) {
        this.minFloor = minF;
        this.maxFloor = maxF;
        this.floorList = fl;
        this.currentFloor = 0;
        this.nextFloor = 0;
        this.index = elevatorCounter++;

        this.goingUp = true;
        this.queue = new HashSet<Integer>();
        
        this.doorClosed = false;
        this.doorActionAttempt = false;
        this.moving = false;
        this.emergencyStop = false;
    }

    /*
     * Logic to calculate where the elevator should go next
     */
    void elevatorAction() {
        //System.out.println(queue);
        if (!this.isMoving() && !this.isQueueEmpty()) {
            this.setDoorClosed(false);
                /*if (!changeDirection) {
                    if (this.goingUp() && (queue.isEmpty() || this.currentFloor >= this.maxFloor)){
                        changeDirection = true;  
                    } else if (!this.goingUp() && (queue.isEmpty() || this.currentFloor <= this.minFloor)){
                        changeDirection = true;
                    } else */if (this.isGoingUp()) {
                        int upMin = this.getQueueMin();
                        
                        if (upMin >= this.minFloor && upMin <= this.maxFloor) {
                            this.nextFloor = upMin;
                            this.moving = true;
                        } else {
                            //System.out.println("ee:" + upMin);
                            //System.out.println("up: neither were appropriate");
                        }
                    } else if (!this.isGoingUp()) {
                        int downMax = this.getQueueMax();

                        if (downMax <= this.maxFloor && downMax >= this.minFloor) {
                            this.nextFloor = downMax;
                            this.moving = true;
                        } else {
                            //System.out.println("down: neither were appropriate");
                        }
                    }
                /*} else if (changeDirection) {
                    changeDirection = false;
                    this.changeDirection();
                    this.setDoorClosed(false);
                }*/
        this.timer = new Date();
        }
    }

    /*
     * Logic to move the elevator to the nextFloor
     */
    void moveElevator() {
        if (this.isMoving() && !this.emergencyStop) {

            if (this.currentFloor == this.nextFloor) {
                this.queue.remove(this.nextFloor);
                //this.doorClosed = false;
                do {
                    this.setDoorClosed(false);
                } while (this.doorClosed);
                this.moving = false;
            } else {
                if ((new Date().getTime() - this.timer.getTime()) > 3000) {
                    if (this.currentFloor < this.nextFloor) { //elevator is moving up
                        int upMin = this.getQueueMin();
                        
                        if (upMin >= this.minFloor && upMin <= this.maxFloor && upMin > this.currentFloor) {
                            this.nextFloor = upMin;
                        }
                        this.changeCurrentFloorUp(true);
                        this.timer = new Date();
                    } else if (this.currentFloor > this.nextFloor) {
                        //this.currentFloor--;
                        int downMax = this.getQueueMax();

                        if (downMax <= this.maxFloor && downMax >= this.minFloor && downMax < this.currentFloor) {
                            this.nextFloor = downMax;
                        }
                        this.changeCurrentFloorUp(false);
                        this.timer = new Date();
                    }
                }
            }

        }
    }

    /*
     * Moves the elevator to the floor
     */
 /*   void moveToFloor(Boolean goUp, int floorSrc) {
        if (floorSrc == this.currentFloor) {
            this.doorClosed = false;
            /*if (this.currentFloor < floorDst){
            this.queueUp.add(floorDst);
            } else if (this.currentFloor > floorDst){
            this.queueDown.add(floorDst);
            }*/
       // } else if (goUp) {
           // this.queueUp.add(floorSrc);
            /*if (floorSrc > this.currentFloor || queueUp.isEmpty()){
            this.queueUp.add(floorSrc);
            } else {
            this.queueUp2.add(floorSrc);
            }*/
       // } else if (!goUp) {
            //this.queueDown.add(floorSrc);
            /*if (floorSrc > this.currentFloor || queueDown.isEmpty()){
            this.queueDown.add(floorSrc);
            } else {
            this.queueDown2.add(floorSrc);
            }*/
      //  }
  //  }
    
    void addToQueue(int floor){
        Boolean addedToQueue = false;
        if (this.isGoingUp()){
            this.queue.add(floor);
        } else if (!this.isGoingUp()){
            this.queue.add(floor);
        }
            
        if (!this.isMoving() && this.currentFloor == floor){
            while(this.isDoorClosed()){
                this.setDoorClosed(false);
            }
        }
    }

    /**
     * Goes to the users destination
     */
  /*  void stopAtFloor(Boolean goUp, int floorDst) {
        stopQueue.add(floorDst);
    }*/

    /**
     * Returns whether the elevator stops at this floor
     */
    boolean goesToFloor(int floorID) {
        return floorList.get(floorID).booleanValue();
    }

    /**
     * Returns whether the is moving
     */
    boolean isMoving() {
        return this.moving;
    }

    /**
     * Returns whether the door is closed
     */
    boolean isDoorClosed() {
        return this.doorClosed;
    }

    /**
     * Set the closing/opening of door
     */
    void setDoorClosed(boolean d) {
        if (!doorActionAttempt) {
            doorTimer = new Date();
            doorActionAttempt = true;
//            doorStateChanged.emit(this.index, d);
        } else if (doorActionAttempt && (new Date().getTime() - doorTimer.getTime()) > 1000) {
            this.doorClosed = d;
            System.out.println("Door closed: " + d);
            this.doorActionAttempt = false;
           // doorStateChanged.emit(this.index, d);
        }
    }
    
    void changeDirection(){
        if (this.goingUp){
            this.goingUp = false;
        } else {
            this.goingUp = true;
        }
        //directionChanged.emit(index, this.goingUp);
    }

    /**
     * Returns the floor the elevator is on
     */
    int getCurrentFloor() {
        return this.currentFloor;
    }

    /**
     * Returns if the elevator is going up or down
     */
    boolean isGoingUp() {
        return this.goingUp;
    }

    /**
     * Adds a person to the counter
     */
    void addPerson() {
        /*     if (goUp){
        this.queueUp.add(floorDst);
        } else {
        this.queueDown.add(floorDst);
        }*/
        this.people++;
       // this.peopleInElevatorChanged.emit(this.index, this.people);
    }

    /*
     * Remove a person from the counter
     */
    void removePerson() {
        this.people--;
        //this.peopleInElevatorChanged.emit(this.index, this.people);
    }

    /**
     * Gets the number of people on the elevator
     */
    int getPeople() {
        return this.people;
    }
    /**
     * Returns true if the elevator is not being used
     */
    boolean isElevatorFree(){
        if (!this.isMoving() && this.queue.isEmpty()){
            return true;
        } else{
            return false;
        }
    }
    
    void changeCurrentFloorUp(boolean increase){
        if (increase){
            this.currentFloor++;
        } else {
            this.currentFloor--;
        }
        //this.currentFloorChanged.emit(this.index, this.currentFloor);
    }
    
    Boolean isQueueEmpty(){
        return this.queue.isEmpty();
    }
    
    int getMinFloor(){
        return this.minFloor;
    }
    
    int getMaxFloor(){
        return this.maxFloor;
    }
    
    static void resetIndex(){
        elevatorCounter = 0;
    }
    
    void setEmergencyStop(boolean stop){
        if (stop){
            this.emergencyStop = true;
        } else {
            this.emergencyStop = false;
            this.timer = new Date();
        }
    }

 /*   int getQueueUpMax() {
        int maximumFloor = Integer.MIN_VALUE;

        Iterator it = queueUp.iterator();
        while (it.hasNext()) {
            int thisFloor = (Integer) it.next();
            if (thisFloor > maximumFloor) {
                maximumFloor = thisFloor;
            }
        }

        return maximumFloor;
    }

    int getQueueUpMin() {
        int minimumFloor = Integer.MAX_VALUE;

        Iterator it = queueUp.iterator();
        while (it.hasNext()) {
            int thisFloor = (Integer) it.next();
            if (thisFloor < minimumFloor) {
                minimumFloor = thisFloor;
            }
        }

        return minimumFloor;
    }

    int getQueueDownMax() {
        int maximumFloor = Integer.MIN_VALUE;

        Iterator it = queueDown.iterator();
        while (it.hasNext()) {
            int thisFloor = (Integer) it.next();
            if (thisFloor > maximumFloor) {
                maximumFloor = thisFloor;
            }
        }

        return maximumFloor;
    }

    int getQueueDownMin() {
        int minimumFloor = Integer.MAX_VALUE;

        Iterator it = queueDown.iterator();
        while (it.hasNext()) {
            int thisFloor = (Integer) it.next();
            if (thisFloor < minimumFloor) {
                minimumFloor = thisFloor;
            }
        }

        return minimumFloor;
    }
*/
    int getQueueMax() {
        int maximumFloor = Integer.MIN_VALUE;
        Iterator it = queue.iterator();
        while (it.hasNext()) {
            int thisFloor = (Integer) it.next();
            if (thisFloor > maximumFloor) {
                maximumFloor = thisFloor;
            }
        }
        return maximumFloor;
    }

    int getQueueMin() {
        int minimumFloor = Integer.MAX_VALUE;
        Iterator it = queue.iterator();
        while (it.hasNext()) {
            int thisFloor = (Integer) it.next();
            if (thisFloor < minimumFloor) {
                minimumFloor = thisFloor;
            }
        }
        return minimumFloor;
    }
    public int getIndex() {
        return index;
    }

    public ArrayList<Boolean> getFloorList() {
        return floorList;
    }

    public Set<Integer> getQueue() {
        return queue;
    }

    public long getTimer() {
        return timer.getTime();
    }

    public long getDoorTimer() {
        return doorTimer.getTime();
    }

    public int getCapacity() {
        return capacity;
    }

    public boolean getDoorActionAttempt() {
        return doorActionAttempt;
    }

    public boolean getEmergencyStop() {
        return emergencyStop;
    }

    public void setTimer(long time) {
        timer.setTime(time);
    }

    public void setDoorTimer(long time) {
        doorTimer.setTime(time);
    }

    public void setCapacity(int capacity) {
        this.capacity = capacity;
    }

    public void setCurrentFloor(int currentFloor) {
        this.currentFloor = currentFloor;
    }

    public void setMoving(Boolean moving) {
        this.moving = moving;
    }

    public void setDoorClosedAttempt(Boolean doorActionAttempt) {
        this.doorActionAttempt = doorActionAttempt;
    }

    public void setQueue(Set<Integer> list) {
        queue = list;
    }

    void setNumberOfPeople(int aInt) {
        people = aInt;
    }
}
